package com.larly.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.larly.common.DelectRequest;
import com.larly.constants.UserConstants;
import com.larly.exception.ErrorCode;
import com.larly.exception.ThrowUtils;
import com.larly.manager.upload.CosManager;
import com.larly.manager.upload.UploadFile;
import com.larly.model.domain.*;
import com.larly.model.dto.user.UserLoginRequest;
import com.larly.model.dto.user.UserQueryRequest;
import com.larly.model.dto.user.UserRegisterRequest;
import com.larly.model.dto.user.UserUpdateRequest;
import com.larly.model.enums.user.UserRoleEnum;
import com.larly.model.vo.UserVO;
import com.larly.service.*;
import com.larly.mapper.UserMapper;
import com.larly.utils.IpAddressUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 许颢达
 * @description 针对表【user(用户表)】的数据库操作Service实现
 * @createDate 2025-08-20 10:37:49
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService{

    private static final String SALT = "larly";

    @Resource
    private UploadFile uploadFile;

    @Resource
    private UserFollowService userFollowService;

    @Resource
    private NotesService notesService;

    @Resource
    private NoteVersionsService noteVersionsService;

    @Resource
    private NoteLikeService noteLikeService;

    @Resource
    private InteractionLikeService interactionLikeService;

    @Override
    public long userRegister(UserRegisterRequest userRegisterRequest) {
        ThrowUtils.throwIf(userRegisterRequest == null, ErrorCode.PARAM_ERROR);
        String username = userRegisterRequest.getUsername();
        String password = userRegisterRequest.getPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        ThrowUtils.throwIf(StrUtil.hasBlank(username, password, checkPassword),ErrorCode.PARAM_ERROR, "账号或者密码为空");
        ThrowUtils.throwIf(username.length() < 4, ErrorCode.PARAM_ERROR, "账号过短");
        ThrowUtils.throwIf(password.length() < 8, ErrorCode.PARAM_ERROR, "密码过短");
        ThrowUtils.throwIf(!password.equals(checkPassword), ErrorCode.PARAM_ERROR, "两次密码不一致");

        // 密码加密
        String encryptPassword = encryptPassword(password);

        // 查询是否注册过
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        User user = this.getOne(queryWrapper);
        ThrowUtils.throwIf(user != null, ErrorCode.PARAM_ERROR, "账号已注册");

        // 保存用户
        User saveUser  = new User();
        saveUser.setUsername(username);
        saveUser.setPassword(encryptPassword);
        saveUser.setAvatar("https://larly-picture-1352810923.cos.ap-beijing.myqcloud.com/blog/avatar.png");
        saveUser.setRole(UserRoleEnum.USER.getKey());

        boolean result = this.save(saveUser);
        ThrowUtils.throwIf(!result, ErrorCode.SYSTEM_ERROR, "注册失败");
        return saveUser.getId();
    }

    @Override
    public UserVO userLogin(UserLoginRequest userLoginRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(userLoginRequest == null, ErrorCode.PARAM_ERROR, "参数为空");
        String username = userLoginRequest.getUsername();
        String password = userLoginRequest.getPassword();
        ThrowUtils.throwIf(StrUtil.hasBlank(username, password),ErrorCode.PARAM_ERROR, "账号或者密码为空");
        ThrowUtils.throwIf(username.length() < 4, ErrorCode.PARAM_ERROR, "账号过短");
        ThrowUtils.throwIf(password.length() < 8, ErrorCode.PARAM_ERROR, "密码过短");

        // 密码加密
        String encryptPassword = encryptPassword(password);

        // 查询用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        queryWrapper.eq("password", encryptPassword);
        User user = this.getOne(queryWrapper);
        ThrowUtils.throwIf(user == null, ErrorCode.PARAM_ERROR, "账号不存在或者密码错误");

        // 转换为VO
        UserVO userVO = userToUserVo(user);
        ThrowUtils.throwIf(userVO == null, ErrorCode.SYSTEM_ERROR, "登录失败，用户转换失败");

        // 保存登录态
        request.getSession().setAttribute(UserConstants.USER_LOGIN_STATE, user);
        return userVO;
    }

    @Override
    public boolean userLogout(DelectRequest delectRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(!isLogin(request), ErrorCode.NOT_LOGIN);

        // 验证登录用户与请求用户是否一致
        User loginUser = getLoginUser(request);
        ThrowUtils.throwIf(!loginUser.getId().equals(delectRequest.getId()), ErrorCode.NO_PERMISSION, "无权限操作");

        // 删除登录态
        request.getSession().removeAttribute(UserConstants.USER_LOGIN_STATE);
        return true;
    }

    @Override
    public User AdminGetById(Integer id) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAM_ERROR, "用户ID无效");
        User user = this.getById(id);
        ThrowUtils.throwIf(user == null, ErrorCode.RESOURCE_NOT_FOUND, "用户不存在");
        return user;
    }

    @Override
    public UserVO getUserVOById(Integer id) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAM_ERROR, "用户ID无效");
        User user = this.getById(id);
        ThrowUtils.throwIf(user == null, ErrorCode.RESOURCE_NOT_FOUND, "用户不存在");
        return userToUserVo(user);
    }

    @Override
    public UserVO userToUserVo(User user) {
        ThrowUtils.throwIf(user == null, ErrorCode.PARAM_ERROR, "用户对象为空");
        // 构造 关注数、粉丝数、笔记数
        UserVO userVO = UserVO.toVO(user);
        // 获取关注者
        Long follow = userFollowService.lambdaQuery().eq(UserFollow::getFollowerId, user.getId()).count();
        userVO.setFollow(follow);
        // 获取粉丝
        Long fans = userFollowService.lambdaQuery().eq(UserFollow::getFollowingId, user.getId()).count();
        userVO.setFans(fans);
        // 获取笔记数
        Long notes = notesService.lambdaQuery().eq(Notes::getUserId, user.getId()).count();
        userVO.setNotes(notes);
        // 获取点赞数
        Long notesAward = noteLikeService.lambdaQuery().eq(NoteLike::getUserId, user.getId()).count();
        Long interactionsAward = interactionLikeService.lambdaQuery().eq(InteractionLike::getUserId, user.getId()).count();
        userVO.setAwards(notesAward + interactionsAward);
        return userVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 事务管理，确保操作原子性
    public boolean deleteUser(DelectRequest deleteRequest, HttpServletRequest request) {
        // 1. 参数校验
        ThrowUtils.throwIf(deleteRequest == null || deleteRequest.getId() == null,
                ErrorCode.PARAM_ERROR, "用户ID不能为空");
        Integer userId = deleteRequest.getId();
        ThrowUtils.throwIf(userId <= 0, ErrorCode.PARAM_ERROR, "用户ID无效");

        // 2. 获取当前登录用户并校验权限
        User loginUser = this.getLoginUser(request);
        // 权限逻辑修正：非管理员只能删除自己的账号
        if (!isAdmin(request) && !loginUser.getId().equals(userId)) {
            ThrowUtils.throwIf(true, ErrorCode.NO_PERMISSION, "无权限删除该用户");
        }

        // 3. 校验用户是否存在
        User user = this.getById(userId);
        ThrowUtils.throwIf(user == null, ErrorCode.RESOURCE_NOT_FOUND, "用户不存在");

        // 4. 执行关联数据删除（按依赖顺序删除，避免外键约束问题）
        // 4.1 删除用户的笔记历史版本
        boolean deleteNoteHistories = deleteUserNoteHistories(userId);
        ThrowUtils.throwIf(!deleteNoteHistories, ErrorCode.SYSTEM_ERROR, "删除用户笔记历史版本失败");

        // 4.2 删除用户的笔记
        boolean deleteNotes = deleteUserNotes(userId);
        ThrowUtils.throwIf(!deleteNotes, ErrorCode.SYSTEM_ERROR, "删除用户笔记失败");

        // 4.3 删除用户的关注关系（包括作为关注者和被关注者的记录）
        boolean deleteFollowRelations = deleteUserFollowRelations(userId);
        ThrowUtils.throwIf(!deleteFollowRelations, ErrorCode.SYSTEM_ERROR, "删除用户关注关系失败");

        // 5. 最后删除用户本身
        boolean deleteUserResult = this.removeById(userId);
        ThrowUtils.throwIf(!deleteUserResult, ErrorCode.SYSTEM_ERROR, "删除用户失败");

        return true;
    }

    /**
     * 删除用户的所有笔记
     */
    private boolean deleteUserNotes(Integer userId) {
        return notesService.lambdaUpdate()
                .eq(Notes::getUserId, userId)
                .remove();
    }

    /**
     * 删除用户的所有笔记历史版本
     * 假设笔记历史表有userId字段或noteId关联，这里以userId为例
     */
    private boolean deleteUserNoteHistories(Integer userId) {
        List<Integer> noteIds = notesService.lambdaQuery()
                .eq(Notes::getUserId, userId)
                .list()
                .stream()
                .map(Notes::getId)
                .collect(Collectors.toList());
        if (CollectionUtil.isEmpty(noteIds)) {
            return true; // 没有笔记则无需删除历史
        }
        return noteVersionsService.lambdaUpdate()
                .in(NoteVersions::getNoteId, noteIds)
                .remove();
    }

    /**
     * 删除用户的所有关注关系（包括关注别人和被别人关注）
     */
    private boolean deleteUserFollowRelations(Integer userId) {
        return userFollowService.lambdaUpdate()
                .eq(UserFollow::getFollowerId, userId)
                .or()
                .eq(UserFollow::getFollowingId, userId)
                .remove();
    }

    @Override
    public boolean updateUser(UserUpdateRequest userUpdateRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(userUpdateRequest == null || userUpdateRequest.getId() == null,
                ErrorCode.PARAM_ERROR, "用户ID不能为空");
        Integer userId = userUpdateRequest.getId();

        // 权限校验
        User loginUser = getLoginUser(request);
        ThrowUtils.throwIf(!loginUser.getId().equals(userId) && !isAdmin(loginUser),
                ErrorCode.NO_AUTH, "无权限修改");

        // 检查用户是否存在
        User existingUser = this.getById(userId);
        ThrowUtils.throwIf(existingUser == null, ErrorCode.RESOURCE_NOT_FOUND, "用户不存在");

        // 构建更新对象
        User updateUser = new User();
        updateUser.setId(userId);

        // 仅更新允许修改的字段
        if (StrUtil.isNotBlank(userUpdateRequest.getNickname())) {
            updateUser.setNickname(userUpdateRequest.getNickname());
        }
        if (StrUtil.isNotBlank(userUpdateRequest.getAvatar())) {
            updateUser.setAvatar(userUpdateRequest.getAvatar());
        }
        if (StrUtil.isNotBlank(userUpdateRequest.getEmail())) {
            updateUser.setEmail(userUpdateRequest.getEmail());
        }
        updateUser.setUpdateTime(new Date());

        boolean result = this.updateById(updateUser);
        ThrowUtils.throwIf(!result, ErrorCode.SYSTEM_ERROR, "更新用户信息失败");
        return true;
    }

    @Override
    public List<UserVO> listUsertolistUserVO(List<User> list) {
        ThrowUtils.throwIf(list == null, ErrorCode.PARAM_ERROR, "用户列表为空");
        return list.stream().map(UserVO::toVO).collect(Collectors.toList());
    }

    @Override
    public QueryWrapper<User> getQueryWrapper(UserQueryRequest userQueryRequest) {
        ThrowUtils.throwIf(userQueryRequest == null, ErrorCode.PARAM_ERROR, "查询参数为空");
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        // 构建查询条件
        if (StrUtil.isNotBlank(userQueryRequest.getUserName())) {
            queryWrapper.like("username", userQueryRequest.getUserName());
        }
        if (StrUtil.isNotBlank(userQueryRequest.getNickname())) {
            queryWrapper.like("nickname", userQueryRequest.getNickname());
        }
        if (userQueryRequest.getStatus() != null) {
            queryWrapper.eq("status", userQueryRequest.getStatus());
        }

        // 排序
        queryWrapper.orderByDesc("create_time");
        return queryWrapper;
    }

    @Override
    public Page<UserVO> listUserVO(UserQueryRequest userQueryRequest) {
        ThrowUtils.throwIf(userQueryRequest == null, ErrorCode.PARAM_ERROR, "查询参数为空");

        // 构建分页参数
        long current = userQueryRequest.getPageNum();
        long size = userQueryRequest.getPageSize();
        Page<User> userPage = this.page(new Page<>(current, size), getQueryWrapper(userQueryRequest));

        // 转换为VO分页对象
        Page<UserVO> userVOPage = new Page<>(current, size, userPage.getTotal());
        userVOPage.setRecords(listUsertolistUserVO(userPage.getRecords()));
        return userVOPage;
    }

    @Override
    public boolean isAdmin(HttpServletRequest request) {
        ThrowUtils.throwIf(request == null, ErrorCode.PARAM_ERROR, "请求为空");
        User user = (User) request.getSession().getAttribute(UserConstants.USER_LOGIN_STATE);
        return isAdmin(user);
    }

    @Override
    public boolean isAdmin(User user) {
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_LOGIN, "用户未登录");
        return UserRoleEnum.ADMIN.getKey().equals(user.getRole());
    }

    @Override
    public User getLoginUser(HttpServletRequest request) {
        ThrowUtils.throwIf(request == null, ErrorCode.PARAM_ERROR, "请求为空");
        User user = (User) request.getSession().getAttribute(UserConstants.USER_LOGIN_STATE);
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_LOGIN, "用户未登录");
        return user;
    }

    @Override
    public boolean uploadAvatar(MultipartFile file, HttpServletRequest request) {
        ThrowUtils.throwIf(file == null, ErrorCode.PARAM_ERROR, "上传文件为空");
        User loginUser = getLoginUser(request);
        String key = String.format("avatar/%s.png", loginUser.getId());
        boolean result = uploadFile.uploadFile(file, key);
        ThrowUtils.throwIf(!result, ErrorCode.FAIL, "上传失败");
        String imgUrl = uploadFile.getImgUrl(key);
        // 更新数据库
        boolean update = this.lambdaUpdate().eq(User::getId, loginUser.getId()).set(User::getAvatar, imgUrl).update();
        ThrowUtils.throwIf(!update, ErrorCode.OPERATION_DENIED, "更新数据库失败");
        return true;
    }

    @Override
    public String getUserRegion(HttpServletRequest request) {
        String ip = IpAddressUtil.getClientIpAddress(request);
        return IpAddressUtil.getRegionByIp(ip);
    }

    // ---------------------- 工具方法 ----------------------

    /**
     * 密码加密
     * @param password 密码
     * @return 加密后的密码
     */
    public String encryptPassword(String password) {
        if(password == null){
            return null;
        }
        return DigestUtils.md5DigestAsHex((password + SALT).getBytes());
    }

    /**
     * 判断用户是否登录
     * @param request 请求
     * @return 是否登录
     */
    public boolean isLogin(HttpServletRequest request) {
        ThrowUtils.throwIf(request == null, ErrorCode.PARAM_ERROR, "请求为空");
        User user = (User) request.getSession().getAttribute(UserConstants.USER_LOGIN_STATE);
        return user != null && user.getId() != null;
    }
}
